package com.zenchn.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zenchn.annotation.OperLog;
import com.zenchn.entity.*;
import com.zenchn.enums.CommonStatusEnum;
import com.zenchn.enums.OperLogActionEnum;
import com.zenchn.enums.SessionAttributeEnum;
import com.zenchn.exception.CheckException;
import com.zenchn.model.*;
import com.zenchn.service.AccountRoleMapperService;
import com.zenchn.service.RoleAuthorityMapperService;
import com.zenchn.service.RoleService;
import com.zenchn.utils.AuthUtils;
import com.zenchn.utils.CommonUtils;
import io.swagger.annotations.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色管理控制器
 *
 * @author dingxinfa
 * @date 2020-04-22
 */
@RestController
@RequestMapping(value = "role")
@Api(value = "角色管理模块相关接口", tags = "用户管理-角色管理")
@RequiresPermissions("role:manage")
public class RoleController {
    private final String MODULE = "用户管理>角色管理";

    @Resource
    private RoleService roleService;

    @Resource
    private RoleAuthorityMapperService roleAuthorityMapperService;

    @Resource
    private AccountRoleMapperService accountRoleMapperService;

    /**
     * 分页获取角色列表
     *
     * @param roleName
     * @param status
     * @param page
     * @param pageSize
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "分页获取角色列表")
    @ApiOperation(value = "分页获取角色列表", notes = "分页获取角色列表")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "roleName", value = "角色名称"),
            @ApiImplicitParam(dataType = "Integer", name = "status", value = "状态"),
            @ApiImplicitParam(dataType = "Integer", name = "page", value = "当前第page页"),
            @ApiImplicitParam(dataType = "Integer", name = "pageSize", value = "每页pageSize数量")
    })
    @GetMapping(value = "/list")
    @RequiresPermissions("role:manage")
    public ResponseEntity<HttpDataResult<PageInfo>> list(
            @RequestParam(required = false, value = "roleName") String roleName,
            @RequestParam(required = false, value = "status") Integer status,
            @RequestParam(required = false, value = "page", defaultValue = "1") Integer page,
            @RequestParam(required = false, value = "pageSize", defaultValue = "10") Integer pageSize,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        HttpDataResult<PageInfo> result = new HttpDataResult<>(request.getRequestURI());
        final TSysAccount currAccount = (TSysAccount) request.getSession().getAttribute(SessionAttributeEnum.CURRENT_ACCOUNT_INFO.getKey());

        TSysAccountRoleMapperExample accountRoleMapperExample=new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(currAccount.getAccountId());
        List<TSysAccountRoleMapper> accountRoleMapperList=accountRoleMapperService.selectByExample(accountRoleMapperExample);

        List<String> roleIds=accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());

        TSysRoleExample currRoleExample=new TSysRoleExample();
        currRoleExample.createCriteria().andRoleIdIn(roleIds);
        Integer roleLevel=roleService.selectByExample(currRoleExample).stream().map(TSysRole::getRoleLevel).min(Integer::compare).orElse(1);

        TSysRoleExample roleExample = new TSysRoleExample();
        TSysRoleExample.Criteria criteria = roleExample.createCriteria();
        criteria.andRoleLevelGreaterThan(roleLevel);

        if (null != roleName && !"".equals(roleName.trim())) {
            criteria.andRoleNameLike("%" + roleName.trim() + "%");
        }
        if (null != status) {
            criteria.andStatusEqualTo(status);
        } else {
            criteria.andStatusGreaterThanOrEqualTo(CommonStatusEnum.DISABLE.getCode());
        }
        roleExample.setOrderByClause("create_time desc");

        PageHelper.startPage(page, pageSize);
        PageInfo pageInfo = new PageInfo(roleService.selectByExample(roleExample));


        List<TSysRole> roleList = pageInfo.getList();
        List<TSysRoleVO> roleVOList = new ArrayList<>();
        for (TSysRole role : roleList) {
            TSysRoleVO roleVO = new TSysRoleVO();
            BeanUtils.copyProperties(role, roleVO);

            roleVO.setStatusName(CommonStatusEnum.getDesc(role.getStatus()));

            roleVOList.add(roleVO);
        }

        pageInfo.setList(roleVOList);

        result.setData(pageInfo);

        result.setMessage("获取角色列表成功.");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /**
     * 获取菜单权限树
     *
     * @param roleId   角色ID
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "获取菜单权限树")
    @ApiOperation(value = "获取菜单权限树", notes = "获取菜单权限树")
    @ApiImplicitParam(dataType = "String", name = "roleId", value = "角色ID，可为空", required = false)
    @GetMapping(value = "/roleAuthTree")
    public ResponseEntity<HttpDataResult<Map<String, Object>>> roleAuthTree(
            @RequestParam(required = false, value = "roleId") String roleId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        HttpDataResult<Map<String, Object>> result = new HttpDataResult<>(request.getRequestURI());
        final TSysAccount currAccount = (TSysAccount) request.getSession().getAttribute(SessionAttributeEnum.CURRENT_ACCOUNT_INFO.getKey());

        TSysAccountRoleMapperExample accountRoleMapperExample=new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(currAccount.getAccountId());
        List<TSysAccountRoleMapper> accountRoleMapperList=accountRoleMapperService.selectByExample(accountRoleMapperExample);

        List<String> roleIds=accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());


        final List<TSysAuthority> authorityList = roleAuthorityMapperService.selectAuthorityByRoleIds(roleIds);

        Map<String, Object> resultData = new HashMap<>(16);
        //树所有列表
        List<AuthTreeVO> authTreeVOList = AuthUtils.treeBuilder(authorityList);
        resultData.put("authTreeList", authTreeVOList);

        //选中的节点code列表
        if (null!=roleId && !"".equals(roleId.trim())){
            List<String> selectedList = roleAuthorityMapperService.selectFullAuthIdbyRoleId(roleId);
            resultData.put("selectedList", selectedList);
        }else{
            resultData.put("selectedList", authorityList.stream().map(TSysAuthority::getAuthId).collect(Collectors.toList()));

        }

        result.setData(resultData);
        result.setMessage("获取角色菜单权限树成功.");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);

    }




    /**
     * 新增角色保存提交
     *
     * @param roleDO
     * @param bindingResult
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.INSERT, detail = "新增角色保存提交")
    @ApiOperation(value = "新增角色保存提交", notes = "新增角色保存提交")
    @ApiParam(type = "TSysRoleDO", name = "roleDO", value = "角色新增映射对象", required = true)
    @PostMapping(value = "/addSubmit")
    @RequiresPermissions("role:manage:add")
    public ResponseEntity<HttpDataResult<String>> addSubmit(
            @RequestBody @Validated TSysRoleDO roleDO, BindingResult bindingResult,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        if (bindingResult.hasErrors()) {
            throw new CheckException(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }

        HttpDataResult<String> result = new HttpDataResult<>(request.getRequestURI());
        final TSysAccount currAccount = (TSysAccount) request.getSession().getAttribute(SessionAttributeEnum.CURRENT_ACCOUNT_INFO.getKey());

        TSysAccountRoleMapperExample accountRoleMapperExample=new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(currAccount.getAccountId());
        List<TSysAccountRoleMapper> accountRoleMapperList=accountRoleMapperService.selectByExample(accountRoleMapperExample);

        List<String> roleIds=accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());

        TSysRoleExample roleExample=new TSysRoleExample();
        roleExample.createCriteria().andRoleIdIn(roleIds);
        Integer roleLevel=roleService.selectByExample(roleExample).stream().map(TSysRole::getRoleLevel).max(Integer::compare).orElse(1);

        String uuid = CommonUtils.randomUUID();

        TSysRole role = new TSysRole();
        BeanUtils.copyProperties(roleDO, role);

        role.setRoleLevel(roleLevel + 1);
        role.setRoleId(uuid);
        role.setRoleSign(uuid);
        role.setCreateTime(LocalDateTime.now());
        role.setIsDefault(false);
        roleService.insert(role);

        roleAuthorityMapperService.updateRoleAuth(role.getRoleId(), roleDO.getAuthIdList());

        result.setData(role.getRoleId());

        result.setMessage("新增角色成功!");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /***
     * 角色详情 （修改页获取数据）
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "角色详情 （修改页获取数据）")
    @ApiOperation(value = "角色详情 （修改页获取数据）", notes = "角色详情 （修改页获取数据）")
    @ApiImplicitParam(dataType = "String", name = "roleId", value = "角色ID", required = true)
    @GetMapping(value = "/detail")
    public ResponseEntity<HttpDataResult<Map<String, Object>>> detail(
            @RequestParam(value = "roleId") String roleId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<Map<String, Object>> result = new HttpDataResult<>(request.getRequestURI());
        Map<String, Object> resultData = new HashMap<>(16);

        TSysRole role = roleService.selectByPrimaryKey(roleId);
        resultData.put("role", role);

        final TSysAccount currAccount = (TSysAccount) request.getSession().getAttribute(SessionAttributeEnum.CURRENT_ACCOUNT_INFO.getKey());
        TSysAccountRoleMapperExample accountRoleMapperExample=new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(currAccount.getAccountId());
        List<TSysAccountRoleMapper> accountRoleMapperList=accountRoleMapperService.selectByExample(accountRoleMapperExample);

        List<String> roleIds=accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());


        final List<TSysAuthority> authorityList = roleAuthorityMapperService.selectAuthorityByRoleIds(roleIds);

        //树所有列表
        List<AuthTreeVO> authTreeVOList = AuthUtils.treeBuilder(authorityList);
        resultData.put("authTreeList", authTreeVOList);

        //选中的节点code列表
        List<String> selectedList = roleAuthorityMapperService.selectFullAuthIdbyRoleId(roleId);
        resultData.put("selectedList", selectedList);


        result.setData(resultData);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /**
     * 修改角色保存提交
     *
     * @param roleDO
     * @param bindingResult
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.UPDATE, detail = "修改角色保存提交")
    @ApiOperation(value = "修改角色保存提交", notes = "修改角色保存提交")
    @ApiParam(type = "TSysRoleDO", name = "roleDO", value = "角色修改映射对象", required = true)
    @PutMapping(value = "/modifySubmit")
    @RequiresPermissions("role:manage:modify")
    public ResponseEntity<HttpDataResult<String>> modifySubmit(
            @RequestBody @Validated TSysRoleDO roleDO, BindingResult bindingResult,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        if (bindingResult.hasErrors()) {
            throw new CheckException(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }

        HttpDataResult<String> result = new HttpDataResult<>(request.getRequestURI());

        TSysRole role = roleService.selectByPrimaryKey(roleDO.getRoleId());
        if (null == role) {
            throw new CheckException("角色ID无效，请检查！");
        }
        if (role.getStatus().equals(CommonStatusEnum.ENABLE.getCode()) && !roleDO.getStatus().equals(CommonStatusEnum.ENABLE.getCode())){
            List<TSysAccount> accountList=accountRoleMapperService.selectAccountByRoleIds(Collections.singletonList(roleDO.getRoleId()));
            if ( null!=accountList && !accountList.isEmpty()) {
                throw new CheckException(String.format("该角色已被相关账户使用，无法[%s]！",CommonStatusEnum.getDesc(roleDO.getStatus())));
            }
        }

        role.setStatus(roleDO.getStatus());
        role.setMemo(roleDO.getMemo());
        role.setRoleName(roleDO.getRoleName());

        roleService.updateByPrimaryKey(role);

        roleAuthorityMapperService.updateRoleAuth(role.getRoleId(), roleDO.getAuthIdList());

        result.setData(role.getRoleId());
        result.setMessage("修改角色成功!");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /***
     *  删除角色
     * @param roleIds
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.DELETE, detail = "删除角色")
    @ApiOperation(value = "删除角色", notes = "删除角色")
    @ApiImplicitParam(dataType = "String", allowMultiple = true, name = "roleIds", value = "角色ID数组 示例[1,2,3,4]", required = true)
    @DeleteMapping(value = "/delete/{roleIds}")
    @RequiresPermissions("role:manage:delete")
    public ResponseEntity<HttpDataResult<Boolean>> delete(
            @PathVariable("roleIds") String[] roleIds,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<Boolean> result = new HttpDataResult<>(request.getRequestURI());


        if (null == roleIds || roleIds.length == 0) {
            throw new CheckException("需要删除的角色ID异常，无法删除！");
        }

        List<String> roleIdList = new ArrayList<>(Arrays.asList(roleIds));

        List<TSysAccount> accountList=accountRoleMapperService.selectAccountByRoleIds(roleIdList);
        if ( null!=accountList && !accountList.isEmpty()) {
            throw new CheckException("需要删除的角色存在关联账户，不允许删除！");
        }

        //删除角色操作
        roleService.deleteRole(roleIdList);

        result.setData(true);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * 批量修改角色列表
     *
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "批量修改角色列表")
    @ApiOperation(value = "批量修改角色列表", notes = "批量修改角色列表")
    @GetMapping(value = "/batchRoleList")
    public ResponseEntity<HttpDataResult<List<TSysRoleVO>>> batchRoleList(
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<TSysRoleVO>> result = new HttpDataResult<>(request.getRequestURI());
        final TSysAccount currAccount = (TSysAccount) request.getSession().getAttribute(SessionAttributeEnum.CURRENT_ACCOUNT_INFO.getKey());

        TSysAccountRoleMapperExample accountRoleMapperExample=new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(currAccount.getAccountId());
        List<TSysAccountRoleMapper> accountRoleMapperList=accountRoleMapperService.selectByExample(accountRoleMapperExample);

        List<String> roleIds=accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());

        TSysRoleExample currRoleExample=new TSysRoleExample();
        currRoleExample.createCriteria().andRoleIdIn(roleIds);
        Integer roleLevel=roleService.selectByExample(currRoleExample).stream().map(TSysRole::getRoleLevel).min(Integer::compare).orElse(1);


        TSysRoleExample roleExample = new TSysRoleExample();
        TSysRoleExample.Criteria criteria = roleExample.createCriteria();
        criteria.andRoleLevelGreaterThan(roleLevel);
        criteria.andStatusGreaterThanOrEqualTo(CommonStatusEnum.DISABLE.getCode());
        roleExample.setOrderByClause("create_time desc");

        List<TSysRole> roleList = roleService.selectByExample(roleExample);
        List<TSysRoleVO> roleVOList = new ArrayList<>();
        for (TSysRole role : roleList) {
            TSysRoleVO roleVO = new TSysRoleVO();
            BeanUtils.copyProperties(role, roleVO);
            roleVO.setStatusName(CommonStatusEnum.getDesc(role.getStatus()));
            roleVOList.add(roleVO);
        }

        result.setData(roleVOList);

        result.setMessage("获取角色列表成功.");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /**
     * 批量修改角色权限提交
     *
     * @param batchDO
     * @param bindingResult
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.UPDATE, detail = "批量修改角色权限提交")
    @ApiOperation(value = "批量修改角色权限提交", notes = "批量修改角色权限提交")
    @ApiParam(type = "TSysRoleDO", name = "batchDO", value = "批量修改角色权限映射对象", required = true)
    @PutMapping(value = "/batchModifyRoleAuthSubmit")
    @RequiresPermissions("role:manage:batch:modify")
    public ResponseEntity<HttpDataResult<Boolean>> batchModifyRoleAuthSubmit(
            @RequestBody @Validated RoleAuthBatchDO batchDO, BindingResult bindingResult,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        if (bindingResult.hasErrors()) {
            throw new CheckException(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }

        HttpDataResult<Boolean> result = new HttpDataResult<>(request.getRequestURI());

        for (String roleId : batchDO.getRoleIdList()) {
            roleAuthorityMapperService.updateRoleAuth(roleId, batchDO.getAuthIdList());
        }

        result.setData(true);
        result.setMessage("批量修改角色权限成功!");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

}
